using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows;
using Caliburn.Micro;
using MediaOwl.Common;
using MediaOwl.Common.ScreenManagement;
using MediaOwl.Common.ViewModels;
using MediaOwl.Cryptos.Resources;
using MediaOwl.Cryptos.Services;

namespace MediaOwl.Cryptos.ViewModels
{
    [Export(typeof(IWorkitem<CryptosViewModel>))]
    public sealed class XorChiffreViewModel : Workitem<CryptosViewModel>
    {
        #region Fields
        private readonly XorChiffre chiffre;
        #endregion

        #region Constructor

        [ImportingConstructor]
        public XorChiffreViewModel(XorChiffre chiffre)
        {
            this.chiffre = chiffre;

            DisplayName = Captions.XorChiffreTitle;
            IsHomeScreen = true;
            Order = 1;
            Description = Captions.XorChiffreDescription;

            rotation = 129d;
            textInput = Captions.DefaultTextInput;
            oneTimePad = false;
            rotationVisibility = Visibility.Visible;
        }

        #endregion

        #region Properties with Backing-Fields
        public string Description { get; private set; }

        private bool oneTimePad;
        public bool OneTimePad
        {
            get { return oneTimePad; }
            set
            {
                oneTimePad = value;
                RotationVisibilityChange();
                NotifyOfPropertyChange(() => OneTimePad);
                NotifyOfPropertyChange(() => NumberShift);
            }
        }
        public bool NumberShift
        {
            get { return !oneTimePad; }
            set
            {
                oneTimePad = !value;
                RotationVisibilityChange();
                NotifyOfPropertyChange(() => NumberShift);
                NotifyOfPropertyChange(() => OneTimePad);
            }
        }

        private double rotation;
        public double Rotation
        {
            get { return rotation; }
            set
            {
                if (value == rotation)
                    return;
                rotation = value;
                NotifyOfPropertyChange(() => Rotation);
            }
        }

        private string textInput;
        public string TextInput
        {
            get { return textInput; }
            set
            {
                textInput = value;
                NotifyOfPropertyChange(() => TextInput);
            }
        }

        private string result;
        public string Result
        {
            get { return result; }
            set
            {
                result = value;
                NotifyOfPropertyChange(() => Result);
            }
        }

        private Visibility rotationVisibility;
        public Visibility RotationVisibility
        {
            get { return rotationVisibility; }
            set
            {
                rotationVisibility = value;
                NotifyOfPropertyChange(() => RotationVisibility);
            }
        }

        public bool CanExecute
        {
            get { return !string.IsNullOrEmpty(TextInput); }
        }

        public bool CanMoveInput
        {
            get { return !string.IsNullOrEmpty(Result); }
        }
        #endregion

        #region Methods

        private void RotationVisibilityChange()
        {
            RotationVisibility = oneTimePad
                    ? Visibility.Collapsed
                    : Visibility.Visible;
        }

        public void Execute()
        {
            Result = oneTimePad
                ? chiffre.EncryptOneTimePad(textInput)
                : chiffre.Encrypt(textInput, (int)rotation);

            NotifyOfPropertyChange(() => CanMoveInput);
        }

        public void MoveInput()
        {
            TextInput = Result;
            Result = string.Empty;
            NotifyOfPropertyChange(() => CanMoveInput);
        }

        public IEnumerable<IResult> ShowDescription()
        {
            yield return Show.Dialog<DialogMessageViewModel>()
                .Configured(x => x.WithData(Description, "Info"));
        }

        #endregion
    }
}